package com.earthea.common.util;

import com.earthea.common.jackson.AnonymizeBeanSerializerModifier;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Jackson工具类
 */
public class JacksonUtils {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private static final ObjectMapper ANONYMIZE_OBJECT_MAPPER = new ObjectMapper();

    static {
        OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        OBJECT_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        OBJECT_MAPPER.registerModule(new JavaTimeModule());

        ANONYMIZE_OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        ANONYMIZE_OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        ANONYMIZE_OBJECT_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        ANONYMIZE_OBJECT_MAPPER.registerModule(new JavaTimeModule());
        // 为Mapper添加匿名化序列化器
        ANONYMIZE_OBJECT_MAPPER.setSerializerFactory(ANONYMIZE_OBJECT_MAPPER.getSerializerFactory().withSerializerModifier(new AnonymizeBeanSerializerModifier()));
    }

    public static ObjectMapper getObjectMapper() {
        return OBJECT_MAPPER;
    }

    public static boolean isJsonMap(String json) {
        try {
            return OBJECT_MAPPER.readTree(json).isObject();
        } catch (JsonProcessingException e) {
            return false;
        }
    }

    public static boolean isJsonArray(String json) {
        try {
            return OBJECT_MAPPER.readTree(json).isArray();
        } catch (JsonProcessingException e) {
            return false;
        }
    }

    private static String toJson(Object obj, boolean pretty, ObjectMapper objectMapper) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof CharSequence) {
            return obj.toString();
        }
        try {
            if (pretty) {
                return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
            }
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("to json failed", e);
        }
    }

    public static String toJson(Object obj, boolean pretty) {
        return toJson(obj, pretty, getObjectMapper());
    }

    public static String toJsonQuietly(Object obj, boolean pretty) {
        try {
            return toJson(obj, pretty, getObjectMapper());
        } catch (IllegalArgumentException ignored) {
            return null;
        }
    }

    public static String toJson(Object obj) {
        return toJson(obj, false);
    }

    public static String toJsonQuietly(Object obj) {
        return toJsonQuietly(obj, false);
    }

    public static String toJsonAnonymize(Object obj) {
        return toJson(obj, false, ANONYMIZE_OBJECT_MAPPER);
    }

    public static <T> T fromJson(String json, Class<T> clazz) {
        if (StringUtils.isBlank(json)) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("from json failed", e);
        }
    }

    public static <T> T fromJsonQuietly(String json, Class<T> clazz) {
        try {
            return fromJson(json, clazz);
        } catch (IllegalArgumentException ignored) {
            return null;
        }
    }

    public static <T> T fromJson(String json, JavaType type) {
        if (StringUtils.isBlank(json)) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(json, type);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("from json failed", e);
        }
    }

    public static <T> T fromJsonQuietly(String json, JavaType type) {
        try {
            return fromJson(json, type);
        } catch (IllegalArgumentException ignored) {
            return null;
        }
    }

    public static <K, V> Map<K, V> fromJsonMap(String json, Class<K> keyType, Class<V> valueType) {
        return fromJson(json, OBJECT_MAPPER.getTypeFactory().constructParametricType(LinkedHashMap.class, keyType, valueType));
    }

    public static <K, V> Map<K, V> fromJsonMapQuietly(String json, Class<K> keyType, Class<V> valueType) {
        try {
            return fromJsonMap(json, keyType, valueType);
        } catch (IllegalArgumentException ignored) {
            return null;
        }
    }

    public static <T> List<T> fromJsonArray(String json, Class<T> clz) {
        return fromJson(json, OBJECT_MAPPER.getTypeFactory().constructParametricType(ArrayList.class, clz));
    }

    public static <T> List<T> fromJsonArrayQuietly(String json, Class<T> clz) {
        try {
            return fromJsonArray(json, clz);
        } catch (IllegalArgumentException ignored) {
            return null;
        }
    }
}
